#pragma once
#include <etcd/Client.hpp>
#include <etcd/Watcher.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Value.hpp>
#include <functional>

#include "logger.hpp"

/*
    提供服务注册 
    服务发现，获取当前所有的能提供服务的信息
    设置服务上线和下线服务的回调函数
*/


//</service/user/instance-1, 127.0.0.1:9000>
class Registery  
{
    public:
    using ptr = std::shared_ptr<Registery>;
    Registery(const std::string& host)
        :_client(std::make_shared<etcd::Client>(host)),
        _keep_alive(_client->leasekeepalive(3).get()),
        _lease_id(_keep_alive->Lease()){}

    ~Registery(){_keep_alive->Cancel();}

    bool registry(const std::string& key,const std::string& val) {
        auto resp = _client->put(key,val,_lease_id).get(); 
        if(resp.is_ok() == false) {
            LOG_ERROR("注册失败：{}",resp.error_message());
            return false; 
        }

        return true;
    }


    private:
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::KeepAlive> _keep_alive;
    uint64_t _lease_id;
};

// 服务发现
class Discovery
{
public:
    using ptr = std::shared_ptr<Discovery>;
    using NotifyCallback = std::function<void(std::string, std::string)>;
    Discovery(const std::string &host,
              const std::string &basedir,
              const NotifyCallback &put_cb,
              const NotifyCallback &del_cb)
        : _client(std::make_shared<etcd::Client>(host)),
          _put_cb(put_cb),
          _del_cb(del_cb)
    {
        auto resp = _client->ls(basedir).get();
        if (resp.is_ok() == false)
        {
            LOG_ERROR("获取服务信息失败: {}", resp.error_message());
        }

        int sz = resp.keys().size();
        for (int i = 0; i < sz; i++)
        {
            if (_put_cb)
                _put_cb(resp.key(i), resp.value(i).as_string());
        }

        // 对事件监控，如果发生了变化，进行回调处理了
        _watcher = std::make_shared<etcd::Watcher>(*_client.get(), basedir, std::bind(&Discovery::callback, this, std::placeholders::_1), true);
    }

    private:
        void callback(const etcd::Response &resp)
        {
            if (resp.is_ok() == false)
            {
                LOG_ERROR("收到一个错误的事件通知", resp.error_message());
                return;
            }

            for (auto const &ev : resp.events())
            {
                // etcd中的事件发生了新增
                if (ev.event_type() == etcd::Event::EventType::PUT)
                {
                    std::cout << "服务信息发生了改变:\n";
                    std::cout << "当前的值：" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl;
                    std::cout << "原来的值：" << ev.prev_kv().key() << "-" << ev.prev_kv().as_string() << std::endl;
                }
                else if (ev.event_type() == etcd::Event::EventType::DELETE_)
                {
                    // etcd中的事件删除了
                    std::cout << "服务信息下线被删除:\n";
                    std::cout << "当前的值：" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl;
                    std::cout << "原来的值：" << ev.prev_kv().key() << "-" << ev.prev_kv().as_string() << std::endl;
                }
            }
        }

    private:
    NotifyCallback _put_cb;
    NotifyCallback _del_cb; 
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::Watcher> _watcher;
};
